﻿#pragma once
#include "Shader.h"
#include "Texture2D.h"

#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <unordered_map>

namespace DYGraphics
{
	struct _declspec(dllexport) MaterialProperty
	{
		enum class Type
		{
			Int = 0,
			Float,
			Float3,
			Float4,
			Matrix,
			Texture,
		};

		Type type;
		union MyUnion
		{
			int intValue = 0;
			float floatValue;
			glm::vec3 vec3Value;
			glm::vec4 vec4Value;
			glm::mat4 mat4;
			Texture2D* texture;
		} data;

		MaterialProperty() {
			type = Type::Int;
		}

		MaterialProperty(int value)
		{
			type = Type::Int;
			data.intValue = value;
		}

		MaterialProperty(float value)
		{
			type = Type::Float;
			data.floatValue = value;
		}

		MaterialProperty(const glm::vec3& value)
		{
			type = Type::Float3;
			data.vec3Value = value;
		}

		MaterialProperty(const glm::mat4& mat4)
		{
			type = Type::Matrix;
			data.mat4 = mat4;
		}

		MaterialProperty(Texture2D* texture)
		{
			type = Type::Texture;
			data.texture = texture;
		}
	};

	class _declspec(dllexport) Material
	{
	public:
		Material() {}

		Material(Shader* shader)
		{
			mShader = shader;
		}

		void SetInt(const std::string& name, int value)
		{
			propMap[name] = MaterialProperty(value);
		}

		void SetFloat(const std::string& name, float value)
		{
			propMap[name] = MaterialProperty(value);
		}

		void SetFloat3(const std::string& name, const glm::vec3& value)
		{
			propMap[name] = MaterialProperty(value);
		}

		void SetFloat4(const std::string& name, const glm::vec4& value)
		{
			propMap[name] = MaterialProperty(value);
		}

		void SetMat4(const std::string& name, const glm::mat4& value)
		{
			propMap[name] = MaterialProperty(value);
		}

		void SetTexture(const std::string& key, Texture2D* texture)
		{
			propMap[key] = MaterialProperty(texture);
		}

		void Setup();
	private:
		Shader* mShader = nullptr;
		std::unordered_map<std::string, MaterialProperty> propMap;
	};
}